#ifndef MATRIX_H_
#define MATRIX_H_

#include <iostream>

// Vorwaertsdeklaration der Matrix Klasse  
template<const int s> class Matrix;

// Deklaration des Template-Ausgabeoperators  
template<const int s> std::ostream& operator<<(std::ostream& out,
		const Matrix<s>& m);

template<const int s> class Matrix
{
	public:
		Matrix()
		{
			reset();
		}

		Matrix(const Matrix<s>& copy)
		{
			for (int i = 0; i < s; i++)
				for (int j = 0; j < s; j++)
					m[i][j] = copy.m[i][j];
		}

		virtual ~Matrix()
		{
		}

		void reset(void)
		{
			for (int i = 0; i < s; i++)
				for (int j = 0; j < s; j++)
					if (i == j)
						m[i][j] = 1.;
					else
						m[i][j] = .0;
		}

		Matrix<s>& multLeft(Matrix<s> left)
		{
			Matrix<s> tmp;
			for (int i = 0; i < s; i++)
				for (int j = 0; j < s; j++)
				{
					tmp.m[i][j] = 0;
					for (int k = 0; k < s; k++)
						tmp.m[i][j] += left.m[i][k] * m[k][j];
				}

			for (int i = 0; i < s; i++)
				for (int j = 0; j < s; j++)
					m[i][j] = tmp.m[i][j];

			return *this;
		}

		Matrix<s>& multRight(Matrix<s> right)
		{
			Matrix<s> tmp;
			for (int i = 0; i < s; i++)
				for (int j = 0; j < s; j++)
				{
					tmp.m[i][j] = 0;
					for (int k = 0; k < s; k++)
						tmp.m[i][j] += m[i][k] * right.m[k][j];
				}

			for (int i = 0; i < s; i++)
				for (int j = 0; j < s; j++)
					m[i][j] = tmp.m[i][j];

			return *this;
		}

		friend std::ostream& operator<< <>(std::ostream& ostr,
				const Matrix<s>& m);

		float m[s][s];
};

template<const int s> std::ostream& operator<<(std::ostream& ostr,
		const Matrix<s>& m)
{
	for (int i = 0; i < s; i++)
	{
		for (int j = 0; j < s; j++)
			ostr << m.m[i][j] << " ";
		ostr << std::endl;
	}
	return ostr;
}

#endif /*MATRIX_H_*/
